﻿/*
* LCL support c# hotfix here.
*Copyright(C) LCL.All rights reserved.
* URL:https://github.com/qq576067421/cshotfix 
*QQ:576067421 
* QQ Group: 673735733 
 * Licensed under the MIT License (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at 
*  
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. 
*/
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using UnityEditor;

namespace LCL
{
    public class Injector
    {
        private static string _assetsPath = "Assets/ILRuntime/Generated/DelegateGen";
        private static string _dllPath = "Library/ScriptAssemblies/Assembly-CSharp.dll";
        private static string m_DllPath;
        private static string m_DelegatePath;

        private static void RefreshPath()
        {
            m_DllPath = Path.GetFullPath(_dllPath);
            m_DelegatePath = Path.GetFullPath(_assetsPath);
        }

        public static void RunGen(string func)
        {
            RefreshPath();

            switch (func)
            {
                case "GenDelegate":
                    {
                        GenDelegate();
                        break;
                    }
                case "InjectIL":
                    {
                        InjectIL();
                        break;
                    }
                case "GenStaticField":
                    {
                        GenDelegate();

                        GenStaticField();
                        break;
                    }
                case "OneKey":
                {
                    OnOneKeyStep("START");
                    break;
                 }
            }
        }

        private static void OnOneKeyStep(string step)
        {
            if ("START" == step)
            {
                EditorUtility.DisplayProgressBar("热更代码生成", "删除文件，等一下...", 0.2f);
                // 删除文件
                var file1 = _assetsPath + "/" + DelegateWriter.DelegateFileName;
                var file2 = _assetsPath + "/" + ILName.FieldDelegateNameFileName;

                SetDoFunctionWhenDidReloadScripts("GEN DELEGATE");

                if (!File.Exists(Path.GetFullPath(file1)) &&
                    !File.Exists(Path.GetFullPath(file2)))
                {
                    // 文件不存在，就直接调用脚本刷新完成的函数吧。
                    OnScriptsReloaded();
                }
                else
                {
                    // 删除文件，重新编译
                    UnityEditor.AssetDatabase.DeleteAsset(file1);
                    UnityEditor.AssetDatabase.DeleteAsset(file2);
                    UnityEditor.AssetDatabase.Refresh();
                }
            }
            else if ("GEN DELEGATE" == step)
            {
                EditorUtility.DisplayProgressBar("热更代码生成", "生成委托类型文件，等一下...", 0.5f);
                RefreshPath();
                GenDelegate();
                UnityEditor.AssetDatabase.Refresh();

                SetDoFunctionWhenDidReloadScripts("GEN DELEGATE NAME");
            }
            else if ("GEN DELEGATE NAME" == step)
            {
                EditorUtility.DisplayProgressBar("热更代码生成", "生成所有代码的委托实体，等一下...", 0.7f);
                RefreshPath();
                // 生成 Filter.NeedInjects
                GenDelegate();
                GenStaticField();
                UnityEditor.AssetDatabase.Refresh();

                SetDoFunctionWhenDidReloadScripts("END");
            }
            else if ("END" == step)
            {
                EditorUtility.ClearProgressBar();
            }
        }

        private static string DoFunctionFileName = "DoFunctionWhenDidReloadScripts.txt";
        private static void SetDoFunctionWhenDidReloadScripts(string v)
        {
            var file = new FileStream(DoFunctionFileName, FileMode.Create);
            var sw = new StreamWriter(file);
            sw.Write(v);
            sw.Flush();
            sw.Close();
            file.Close();
        }

        private static string GetDoFunctionWhenDidReloadScripts()
        {
            if (!File.Exists(DoFunctionFileName))
            {
                return "";
            }

            var file = new FileStream(DoFunctionFileName, FileMode.Open);
            var sw = new StreamReader(file);
            var functionName = sw.ReadLine();
            sw.Close();
            file.Close();
            File.Delete(DoFunctionFileName);

            return functionName;
        }

        [UnityEditor.Callbacks.DidReloadScripts]
        private static void OnScriptsReloaded()
        {
            var functionName = GetDoFunctionWhenDidReloadScripts();
            //UnityEngine.Debug.LogError("OnScriptsReloaded : " + functionName);
            if (!string.IsNullOrEmpty(functionName))
            {
                OnOneKeyStep(functionName);
            }
        }


        private static void GenDelegate()
        {
            DelegateGen delegateGen = new DelegateGen();
            delegateGen.Run(m_DllPath, m_DelegatePath);
            UnityEngine.Debug.Log("GenDelegate Ok!");

        }
        private static void InjectIL()
        {

            InjectorMain inject = new InjectorMain();
            inject.Run(m_DllPath, m_DelegatePath, false);
            UnityEngine.Debug.Log( "Inject Ok!");
        }
        private static void GenStaticField()
        {
            InjectorMain inject = new InjectorMain();
            inject.Run(m_DllPath, m_DelegatePath, true);
            UnityEngine.Debug.Log("GenStaticField Ok!");
        }

    }
}
